djinnifandomcom_pl-20200213-history
Animacje w skryptach
Dwa sposoby na odtworzenie animacji Funkcja PlayAnimation() Używając funkcji PlayAnimation() możemy odtworzyć animacje natychmiast nie zważając na kontekst // Play nAnimation immediately. // - nAnimation: ANIMATION_* // - fSpeed // - fSeconds void PlayAnimation(int nAnimation, float fSpeed=1.0, float fSeconds=0.0); Funkcja ActionPlayAnimation() Alternatywnie, możemy użyć funkcji ActionPlayAnimation(). Powstanie kolejka animacji i odtworzenie ich zgodnie z kolejnością. (zobacz Kolejka w skryptach) // Cause the action subject to play an animation //-nAnimation: ANIMATION_* // -fSpeed: Speed of the animation // -fDurationSeconds: Duration of the animation (this is not used for Fire and // Forget animations) void ActionPlayAnimation(int nAnimation, float fSpeed=1.0, float fDurationSeconds=0.0); Ustalenie celu Najlepszym sposobem do odtworzenia animacji jest fizyczne ustalenie pożądanego celu używając funkcji AssignCommand(): AssignCommand(OTARGET,ActionPlayAnimation(ANIMATION_*)); Stałe animacji ANIMATION_* (przykład u góry) jest trwale ustawiona w pliku nwscriptdefn.nss, który możemy znaleźć w katalogu “The Witcher\System\Scripts”. Chociaż ten plik zawiera dużo stałych i funkcji używanych przez D'jinni'ego, tylko tam jest względnei krótka lista Stałych animacji. // Looping animation constants. int ANIMATION_LOOPING_PAUSE = 0; int ANIMATION_LOOPING_PAUSE2 = 1; int ANIMATION_LOOPING_LISTEN = 2; int ANIMATION_LOOPING_MEDITATE = 3; int ANIMATION_LOOPING_WORSHIP = 4; int ANIMATION_LOOPING_LOOK_FAR = 5; int ANIMATION_LOOPING_SIT_CHAIR = 6; int ANIMATION_LOOPING_SIT_CROSS = 7; int ANIMATION_LOOPING_TALK_NORMAL = 8; int ANIMATION_LOOPING_TALK_PLEADING = 9; int ANIMATION_LOOPING_TALK_FORCEFUL = 10; int ANIMATION_LOOPING_TALK_LAUGHING = 11; int ANIMATION_LOOPING_GET_LOW = 12; int ANIMATION_LOOPING_GET_MID = 13; int ANIMATION_LOOPING_PAUSE_TIRED = 14; int ANIMATION_LOOPING_PAUSE_DRUNK = 15; int ANIMATION_LOOPING_DEAD_FRONT = 16; int ANIMATION_LOOPING_DEAD_BACK = 17; int ANIMATION_LOOPING_CONJURE1 = 18; int ANIMATION_LOOPING_CONJURE2 = 19; int ANIMATION_LOOPING_SPASM = 20; int ANIMATION_LOOPING_WORK1 = 21; int ANIMATION_LOOPING_WORK2 = 22; int ANIMATION_LOOPING_WORK3 = 23; int ANIMATION_LOOPING_WORK4 = 24; int ANIMATION_LOOPING_WORK5 = 25; int ANIMATION_LOOPING_POSE_CALM = 26; int ANIMATION_LOOPING_POSE_CHEER = 27; int ANIMATION_LOOPING_POSE_EXCITED = 28; int ANIMATION_LOOPING_POSE_NERVOUS = 29; int ANIMATION_LOOPING_GEST_TALK = 30; int ANIMATION_LOOPING_GEST_SPEECH = 31; int ANIMATION_LOOPING_GEST_MONOLOGUE = 32; int ANIMATION_LOOPING_GEST_AMUSED = 33; int ANIMATION_LOOPING_GEST_TIRED = 34; int ANIMATION_LOOPING_GEST_BORED = 35; int ANIMATION_LOOPING_GEST_THREAT = 36; int ANIMATION_LOOPING_GEST_RETREAT = 37; int ANIMATION_LOOPING_GEST_ASSURE = 38; int ANIMATION_LOOPING_GEST_RESOLUTE = 39; int ANIMATION_LOOPING_GEST_JOKE = 40; // Fire and forget animation constants. int ANIMATION_FIREFORGET_HEAD_TURN_LEFT = 100; int ANIMATION_FIREFORGET_HEAD_TURN_RIGHT = 101; int ANIMATION_FIREFORGET_PAUSE_SCRATCH_HEAD = 102; int ANIMATION_FIREFORGET_PAUSE_BORED = 103; int ANIMATION_FIREFORGET_SALUTE = 104; int ANIMATION_FIREFORGET_BOW = 105; int ANIMATION_FIREFORGET_STEAL = 106; int ANIMATION_FIREFORGET_GREETING = 107; int ANIMATION_FIREFORGET_VICTORY1 = 109; int ANIMATION_FIREFORGET_VICTORY2 = 110; int ANIMATION_FIREFORGET_VICTORY3 = 111; int ANIMATION_FIREFORGET_READ = 112; int ANIMATION_FIREFORGET_DRINK = 113; int ANIMATION_FIREFORGET_DODGE_SIDE = 114; int ANIMATION_FIREFORGET_DODGE_DUCK = 115; int ANIMATION_FIREFORGET_GEST_BOW = 116; int ANIMATION_FIREFORGET_GEST_YAWN = 117; int ANIMATION_FIREFORGET_GEST_INVITE = 118; int ANIMATION_FIREFORGET_GEST_SALUTE = 119; int ANIMATION_FIREFORGET_TELEPORT_PRE = 120; int ANIMATION_FIREFORGET_TELEPORT_POST = 121; int ANIMATION_FIREFORGET_SPECIAL1 = 122; int ANIMATION_FIREFORGET_SPECIAL2 = 123; int ANIMATION_FIREFORGET_SPECIAL3 = 124; int ANIMATION_FIREFORGET_SPECIAL4 = 125; int ANIMATION_ELIXIR_7 = 126; int ANIMATION_VANISH = 127; int ANIMATION_FIREFORGET_ELIXIR_EFFECT = 174; // Placeable animation constants int ANIMATION_PLACEABLE_ACTIVATE = 200; int ANIMATION_PLACEABLE_DEACTIVATE = 201; int ANIMATION_PLACEABLE_OPEN = 202; int ANIMATION_PLACEABLE_CLOSE = 203; int ANIMATION_PLACEABLE_DEAD = 204; int ANIMATION_DOOR_OPEN1 = 300; int ANIMATION_DOOR_OPEN2 = 301; int ANIMATION_DOOR_CLOSED = 302; Porównując do klasycznej defincji skryptu NWN, gdzie 200, lub więcej animacji są spisane jako “wspólne” dla każdej postaci, jest to bardzo krótka lista! Pechowo, wytłumaczenei jest niekompletne, kryje się za tym logika. Wbudowane animacje głównego bohatera Jeśli chcesz użyć, która nei jest wymieniona w tej liście, (obejrzyj screena).' Pytania i hipotezy Odpowiedzi na pytania: *Jak możemy połączyć te wbudowane animacje w jedną aniamcje skryptową? Aby odpowiedzieć na to pytanie spędziliśmy mnóstwo czasu na studiowaniu silnika. Omówmy kilka rzeczy: *Na samym początku, odwołajmy się do animacji bez opisanych stałych w pliku '''nwdefscript.nss', nie znajdziemy żadnej ukrytej wartości przewodzącej animacji—ale jest tam parę rzeczy, których jeszcze nie znaleźliśmy. *Zbadajmy ogólne funkcjonowanie plików 2DA, aby zrozumieć jak parę animacji może być odtworzona bez stałych. (spójrz na dział efektów zaklęć po więcej szczegółów). *Możemy zrobić własne animacje przez zapełnienie kolejnej “pustki”, ale określenie gniazd. ANIMATION_FIREFORGET_SPECIAL1-5 *Przetestowaliśmy mnóstwo różnych funkcji przeznaczonych do animacji i efektów. Animacje i efekty są zdefiniowane w D'jinnim, ale nie zwykłym typem. Na dodatek, efekty nie pracują jak animacje, ponieważ maja specjalne zadedykowane funkcje, co umożliwia odwrócenie każdego efektu opartego na stałych. *Dla przykładu rozpatrzmy taki kod: effect efly; eFly = EffectVisualEffect(EFFECT_TYPE_APPLY_RUNNING_EFFECT,FALSE); eFly = EffectDisappearAppear(lLocTarget); eFly = EffectAppear(); Nie jest on stworzony dla animacji. Wniosek odnośnie tego: *Jest mnóstwo wyciętych i zmodyfikowanych danych struktury głównej pomiędzy NWN i Wiedźminem. W Wiedźminie, dane nie są tak samo dostępne, i mnóstwo z nich są ukryte w silniku i niedostępne na ogół w skryptowaniu. Przyjmujemy, że kiedy animacje jest umieszczona w lokacji, i ta lokacja zawiera tylko silnik lub główne animacje, NIE SĄ używane w skryptowaiu. Myślimy, że gdzieś te wyraźnie używane animacje są zdefiniowane (dostępne bezpośrednio zmienne)—mogą być kombinacja głównych animacji. Jest to rodzaj fasady, bądź warstwy do ukrycia pełną animacji skryptów. Prawdopodobnie należą do specyficznych animacji postaci nie wpisane do listy wszystkich elementów. Efekty zaklęć : Jak to działa. Efekty zaklęć są o wiele inne niż te używane w NWN. Niespecyficzna stała jest zdefiniowana jak w systemie NWN, lecz trochę bardziej złożona. Trochę innych funkcji: // The action subject will fake casting a spell at oTarget; the conjure and cast // animations and visuals will occur, nothing else. // - nSpell // - oTarget // - nProjectilePathType: PROJECTILE_PATH_TYPE_* void ActionCastFakeSpellAtObject(int nSpell, object oTarget, int nProjectilePathType=PROJECTILE_PATH_TYPE_DEFAULT); Funkcja zawsze pobiera całość do ustalenia klasy zaklęcia. Niemniej jednak, ta całość nie kieruje wyborem stałej, a ciąg w pliku 2DA. Plik spells.2da zawiera mnóstwo dodatkowych informacji o zaklęciach i sposobu ich rzucania. Spójrzmy na to (screen): Możesz zobaczyć, że zaklęcie ma więcej niż jedną linię. Jest ich właściwie dla pozomu wybranego zaklęcia. Zależnei od poziomu parametry sie zmieniają (czas trwania, siła, efekty wizualne i inne) Mozesz, także, zobaczyć kolumne nazwaną "ImpactScript", która pozwala na odtworzenie specjalnego skryptu zależnie od klasy zaklęcia. Oznacza to, że inne rzeczy odpowiadają za różne wartości(obrażenia i inne) Jako przypomnienie, jest możliwe odtworzenie skryptu przez jego nazwę używając funkcji ExecuteScript Kiedy przejdziemy dalej, zobaczymy dwie rózne kolumny: ConjAnim i CastAnim. Mogą być kluczowe do zdefiniowania animacji podczas zrzucania zaklęcia. To wydaje się koniec wewnętrzny skoro nie mogę zdobyć żadnego tropu... Powróćmy do odtwarzania bezpośrednio wbudowanych funkcji. // SPELL_SUBTYPE_X Funkcja do odnalezienia “X”: int FindSpellByTypeAndLevel(string sType, int nSubtype, int nLevel); Tutaj powszechne użycie tej funkcji w istniejących skryptach dla AI: case COMBAT_HEAL: { DClearAllActions(FALSE, oSource); object oWounded = _GetWounded(oSource); int nSpell = FindSpellByTypeAndLevel("Heal", SPELL_SUBTYPE_NORMAL, 0); AssignCommand(oSource, ActionCastSpellAtObject(nSpell, oSource, TRUE)); _SetWounded(oSource, oSource); break; } from inc_ai.nss Pierwszy parametr określa klasę zalęcia (HEAL, AARD, IGNI...). Drugi może być też SPELL_SUBTYPE_NORMAL lub SPELL_SUBTYPE_ (SpellSubType) i nLevel wybierze poziom zaklęcia mającego klasę w >> column spellLevel. Wtedy poprawi linie i odtworzy zaklęcie To wszystko o efektach zaklęć. 'Autor MacGuiness and Fabien Ducat, tłumaczenie: Michał "Quarties" Sypko ' Kategoria:Skrypty